package com.molyfun.parents.service.music;

import android.content.Context;
import android.media.AudioManager;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 此类是用于音乐Focus的管理类，
 * OnAudioFocusChangeListener Added in API level 8
 * 此处使用动态代理
 * @author liuchao6@staff.sina.com.cn
 */

public class AudioFocusHelper{
    
    private static final String TAG = "AudioFocusHelper";
    public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
    public static final int AUDIOFOCUS_GAIN_TRANSIENT_NO_DUCK = 2;
    private static final int AUDIOMANAGER_AUDIOFOCUS_GAIN = 1;
    private static final int AUDIOMANAGER_AUDIOFOCUS_LOSS = -1;
    private static final int AUDIOMANAGER_AUDIOFOCUS_LOSS_TRANSIENT = -2;
    private static final int AUDIOMANAGER_AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK = -3;
    AudioManager mAM;
    private Object mOnAudioFocusChangeListener = null;
    IMusicFocusable mFocusable;

    public AudioFocusHelper(Context ctx, IMusicFocusable focusable) {
        mAM = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE);
        mFocusable = focusable;
        setOnAudioFocusChangeListener();
    }
    
    public void setOnAudioFocusChangeListener() {
        Class<?>[] innerClasses = mAM.getClass().getDeclaredClasses();
        for (Class<?> interfaze : innerClasses) {
            if (interfaze.getSimpleName().equalsIgnoreCase("OnAudioFocusChangeListener")) {
                Class<?>[] classArray = new Class<?>[1];
                classArray[0] = interfaze;
                mOnAudioFocusChangeListener = Proxy.newProxyInstance(interfaze.getClassLoader(), classArray, new ProxyOnAudioFocusChangeListener());
            }
        }

    }

    public boolean requestFocus() {
//       return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==
//            mAM.requestAudioFocus(this, AudioManager.STREAM_ MUSIC, AudioManager.AUDIOFOCUS_GAIN);
        
        if (mOnAudioFocusChangeListener != null) {
            try {
                Method[] methods = mAM.getClass().getDeclaredMethods();
                for (Method method : methods) {
                    if (method.getName().equalsIgnoreCase("requestAudioFocus"))
                    {
                        method.invoke(mAM, mOnAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AUDIOMANAGER_AUDIOFOCUS_GAIN);
                    }
                }
                return true;
            } catch (Exception e) {
//                LogUtil.e(TAG, e.getMessage());
                return false;
            }
        }
        return false;
    }
    
    public boolean requestFocus(int autoFocusGainType) {
//       return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==
//            mAM.requestAudioFocus(this, AudioManager.STREAM_ MUSIC, AudioManager.AUDIOFOCUS_GAIN);
        
        if (mOnAudioFocusChangeListener != null) {
            try {
                Method[] methods = mAM.getClass().getDeclaredMethods();
                for (Method method : methods) {
                    if (method.getName().equalsIgnoreCase("requestAudioFocus"))
                    {
                        method.invoke(mAM, mOnAudioFocusChangeListener, AudioManager.STREAM_MUSIC, autoFocusGainType);
                    }
                }
                return true;
            } catch (Exception e) {
//                LogUtil.e(TAG, e.getMessage());
                return false;
            }
        }
        return false;
    }

    public boolean abandonFocus() {
//        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED == mAM.abandonAudioFocus(this);
        if (mOnAudioFocusChangeListener != null) {
//            LogUtil.i(TAG, "releaseAudioFocus()");
            try {
                Method[] methods = mAM.getClass().getDeclaredMethods();
                for (Method method : methods) {
                    if (method.getName().equalsIgnoreCase("abandonAudioFocus"))
                        method.invoke(mAM, mOnAudioFocusChangeListener);
                }
                return true;
            } catch (Exception e) {
//                LogUtil.e(TAG, e.getMessage());
                return false;
            }
        }
        return false;
    }

    
    private class ProxyOnAudioFocusChangeListener implements InvocationHandler {

        public void onAudioFocusChange(int focusChange) {
            if (mFocusable == null) {
                return;
            }
            switch (focusChange) {
            case AUDIOMANAGER_AUDIOFOCUS_GAIN:
                mFocusable.onGainedAudioFocus();
                break;
            case AUDIOMANAGER_AUDIOFOCUS_LOSS:
            case AUDIOMANAGER_AUDIOFOCUS_LOSS_TRANSIENT:
                mFocusable.onLostAudioFocus(false);
                break;
            case AUDIOMANAGER_AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                mFocusable.onLostAudioFocus(true);
                break;
             default:
        }
        }

        // implements the method invoke from the InvocationHandler interface
        // it intercepts the calls to the listener methods
        // in this case it redirects the onAudioFocusChange listener method to the OnAudioFocusChange proxy method
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result = null;
            try {
                if (args != null) {
                    if (method.getName().equals("onAudioFocusChange") && args[0] instanceof Integer) {
                        onAudioFocusChange((Integer) args[0]);
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException("unexpected invocation exception: " + e.getMessage());
            }
            return result;
        }
    }

}
